package com.ruoyi.wx.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.dddetails.domain.DdDetails;
import com.ruoyi.dddetails.mapper.DdDetailsMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.user.domain.User;
import com.ruoyi.user.domain.vo.ExpertLoginVO;
import com.ruoyi.user.domain.vo.ExpertPwd;
import com.ruoyi.user.mapper.UserMapper;
import com.ruoyi.wx.config.WxV3PayConfig;
import com.ruoyi.wx.service.WxLoginService;
import com.ruoyi.wx.utils.*;
import com.ruoyi.wx.vo.WxLoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxLoginServiceImpl implements WxLoginService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Qualifier("tokenService1")
    private TokenService tokenService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private DdDetailsMapper ddDetailsMapper;

    @Autowired
    private org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder passwordEncoder;

    @Transactional
    @Override
    public AjaxResult wxLogin(WxLoginVo wxLoginVo) {
        try {
            AjaxResult ajax = AjaxResult.success();
            // 微信小程序ID
            String appid = WxV3PayConfig.APP_ID;
            // 微信小程序秘钥
            String secret = WxV3PayConfig.secret;

            // 根据小程序穿过来的code想这个url发送请求
            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + wxLoginVo.getCode() + "&grant_type=authorization_code";
            // 发送请求，返回Json字符串
            String str = WeChatUtil.httpRequest(url, "GET", null);
            // 转成Json对象 获取openid
            JSONObject jsonObject = JSONObject.parseObject(str);
            // 我们需要的openid，在一个小程序中，openid是唯一的
            String openid = jsonObject.get("openid").toString();
            String sessionKey = jsonObject.get("session_key").toString();
            wxLoginVo.setSessionKey(sessionKey);
            User user = new User();
            if (StringUtils.isNotEmpty(openid)) {
                String phoneNumber = this.getPhoneNumber(wxLoginVo);
                //先用电话号码判断有无此用户
                String userName = phoneNumber;
                user.setUsername(userName);
                user.setIsExpert(1L);
                user = userMapper.selectUserByUsername(user);

                String nickName = NameUtil.getName();

                //用户不存在
                if (user == null) {
                    // 查询当前最大 id
                    Integer maxId = userMapper.selectMaxId();
                    int nextId = maxId == null ? 1 : maxId + 1;

                    // 前补零，生成 6 位 user_id
                    String userId = String.format("%06d", nextId);
                    //保存用户信息
                    user = new User();
                    user.setUserId(userId);
                    user.setInvitationCode(userId);
                    user.setNickname(nickName);
                    user.setUsername(userName);
                    user.setPhone(phoneNumber);
                    user.setIsExpert(1L);
                    user.setPassword(passwordEncoder.encode("123456"));
                    user.setOpenId(openid);
                    user.setCreateTime(DateUtils.getNowDate());
                    user.setDdTotalNumber(BigDecimal.valueOf(20));
                    user.setCumulativeDd(BigDecimal.valueOf(20));
                    String inviterId = wxLoginVo.getInviterId();
                    if (inviterId != null && !"".equals(inviterId)) {
                        DdDetails ddDetails1 = new DdDetails();
                        ddDetails1.setId(inviterId);
                        ddDetails1.setSource("邀请收益");
                        ddDetails1.setDetails("+5.00");
                        ddDetails1.setCreateTime(new Date());
                        ddDetailsMapper.insertDdDetails(ddDetails1);
                        User user1 = userMapper.selectUserByUserId(inviterId);
                        BigDecimal ddTotalNumber = user1.getDdTotalNumber();
                        user1.setDdTotalNumber(ddTotalNumber.add(BigDecimal.valueOf(5)));
                        user1.setCumulativeDd(user1.getCumulativeDd().add(BigDecimal.valueOf(5)));
                        user.setInviterId(inviterId);
                        userMapper.updateUser(user1);
                    }
                    DdDetails ddDetails = new DdDetails();
                    ddDetails.setId(userId);
                    ddDetails.setSource("注册收益");
                    ddDetails.setDetails("+20.00");
                    ddDetails.setCreateTime(DateUtils.getNowDate());
                    ddDetailsMapper.insertDdDetails(ddDetails);
                    userMapper.insertUser(user);
                } else {
                    User user1 = userMapper.selectUserByUserId(user.getUserId());
                    if (StringUtils.isEmpty(user1.getOpenId())) {
                        user1.setOpenId(openid);
                    }
                    userMapper.updateUser(user1);
                }
                //用户存在
                String token = this.login2(user.getUsername(), "123456", 1L);
                ajax.put(Constants.TOKEN, token);
            }
            return ajax;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException("登录失败，请联系管理员！");
        }
    }

    /**
     * 退出登录
     *
     * @return
     */
    @Override
    public AjaxResult logout(HttpServletRequest request) {
        return GetUserUtils.logout(request);
    }

    /**
     * 专家登录
     *
     * @param expertLoginVO
     * @return
     */
    @Override
    @Transactional
    public AjaxResult expertLogin(ExpertLoginVO expertLoginVO) {
        try {
            AjaxResult ajax = AjaxResult.success();
            String token = this.login2(expertLoginVO.getUsername() + "__expert", expertLoginVO.getPassword(), 0L);
            User user1 = new User();
            user1.setUsername(expertLoginVO.getUsername() + "__expert");
            user1.setIsExpert(0L);
            User user = userMapper.selectUserByUsername(user1);
            String openId = user.getOpenId();
            if (openId == null) {
                // 微信小程序ID
                String appid = WxV3PayConfig.APP_ID_EXPERT;
                // 微信小程序秘钥
                String secret = WxV3PayConfig.APP_SECRET_EXPERT;

                // 根据小程序穿过来的code想这个url发送请求
                String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + expertLoginVO.getWxCode() + "&grant_type=authorization_code";
                // 发送请求，返回Json字符串
                String str = WeChatUtil.httpRequest(url, "GET", null);
                // 转成Json对象 获取openid
                JSONObject jsonObject = JSONObject.parseObject(str);
                // 我们需要的openid，在一个小程序中，openid是唯一的
                String openid = jsonObject.get("openid").toString();
                user.setOpenId(openid);
                userMapper.updateUser(user);
            }
            ajax.put(Constants.TOKEN, token);
            return ajax;
        } catch (UserPasswordNotMatchException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            log.error("登录异常", e);
            return AjaxResult.error("登录失败");
        }
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(String userId) {
        User user = new User();
        user.setUserId(userId);
        user.setIp(IpUtils.getIpAddr());
        user.setLoginDate(DateUtils.getNowDate());
        userMapper.updateUser(user);
    }

    public String login2(String username, String password, Long isExpert) {
        // 直接查询你自己的 user 表
        User user1 = new User();
        user1.setUsername(username);
        user1.setIsExpert(isExpert);
        User user = userMapper.selectUserByUsername(user1);
        if (user == null) {
            // 直接打印日志或者调用你自己的日志记录方法
            log.warn("登录失败，用户不存在，用户名：" + username);
            throw new UserPasswordNotMatchException("用户不存在");
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            log.warn("登录失败，密码错误，用户名：" + username);
            throw new UserPasswordNotMatchException("密码错误");
        }

        // 登录成功，记录登录信息
        log.info("用户登录成功，用户名：" + username);
        recordLoginInfo(user.getUserId());


        // 封装自定义登录用户
        User loginUser = new User();
        loginUser.setUserId(user.getUserId());
        loginUser.setUsername(user.getUsername());
        loginUser.setIp(IpUtils.getIpAddr());

        // 生成 Token（存到 Redis）
        String token = "Bearer " + UUID.randomUUID().toString().replace("-", "");
        loginUser.setToken(token);

        // 保存到 Redis (用 RuoYi 的 RedisUtils 或自己的)
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        redisCache.setCacheObject(WxConstants.LOGIN_TOKEN_KEY + token, loginUser, WxConstants.TOKEN_EXPIRE, TimeUnit.MINUTES);

        return token;
    }


    public String getPhoneNumber(WxLoginVo getPhoneVo) throws Exception {

        //获取accessToken
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"
                + "?access_token=" + accessToken;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", getPhoneVo.getPhoneCode());
        String reqJsonStr = JSONObject.toJSONString(jsonObject);
        JSONObject wxJson = JSON.parseObject(HttpClientSslUtils.doPost(url, reqJsonStr));
        String phone_info = wxJson.getString("phone_info");
        JSONObject phone_info1 = JSONObject.parseObject(phone_info);
        String phoneNumber = null;
        try {
            phoneNumber = phone_info1.getString("phoneNumber");
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException("获取用户手机号失败！");
        }
        return phoneNumber;

    }

    private String getAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token" +
                "?grant_type=client_credential" +
                "&appid=" + WxV3PayConfig.APP_ID +
                "&secret=" + WxV3PayConfig.secret;

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        String responseBody = responseEntity.getBody();
        JSONObject jsonObject = JSONObject.parseObject(responseBody);

        return jsonObject.getString("access_token");
    }


    /**
     * 专家注册
     *
     * @param expertLoginVO
     * @return
     */
    @Override
    @Transactional
    public AjaxResult register(ExpertLoginVO expertLoginVO) {
        String code = expertLoginVO.getCode();
        String phone = expertLoginVO.getUsername();

        // 获取 RedisCache Bean
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        String redisKey = "sms:code:" + phone;

        // 从 Redis 取出验证码
        String redisCode = redisCache.getCacheObject(redisKey);
        if (redisCode == null) {
            return AjaxResult.error("验证码已过期，请重新获取");
        } else if (!redisCode.equals(code)) {
            return AjaxResult.error("验证码错误");
        } else {
            User user = new User();
            user.setUsername(expertLoginVO.getUsername() + "__expert");
            user.setPassword(expertLoginVO.getPassword());
            // 先查询是否已经注册
            user.setIsExpert(0L);
            User user1 = userMapper.selectUserByUsername(user);
            if (user1 != null) {
                return AjaxResult.error("账号已注册");
            } else {
                String nickName = NameUtil.getName();
                // 查询当前最大 id
                Integer maxId = userMapper.selectMaxId();
                int nextId = maxId == null ? 1 : maxId + 1;
                // 前补零，生成 6 位 user_id
                String userId = String.format("%06d", nextId);
                user.setUserId(userId);
                user.setInvitationCode(userId);
                user.setPhone(expertLoginVO.getUsername());
                String password = passwordEncoder.encode(user.getPassword());
                user.setPassword(password);
                user.setCreateTime(DateUtils.getNowDate());
                // 注册叮豆
                user.setDdTotalNumber(BigDecimal.valueOf(20));
                user.setCumulativeDd(BigDecimal.valueOf(20));
                // 专家状态
                user.setUserStatus("0");
                user.setTotalAmount(BigDecimal.valueOf(0));
                user.setFreezeAmount(BigDecimal.valueOf(0));
                user.setWithdrawableAmount(BigDecimal.valueOf(0));
                user.setNickname(nickName);
                user.setIsExpert(0L);
                user.setQualificationsInt(0);
                DdDetails ddDetails = new DdDetails();
                ddDetails.setId(userId);
                ddDetails.setCreateTime(DateUtils.getNowDate());
                ddDetails.setSource("注册收益");
                ddDetails.setDetails("+20.00");
                ddDetailsMapper.insertDdDetails(ddDetails);
                String inviterId = expertLoginVO.getInviterId();
                if (inviterId != null && !"".equals(inviterId)) {
                    DdDetails ddDetails1 = new DdDetails();
                    ddDetails1.setId(inviterId);
                    ddDetails1.setSource("邀请收益");
                    ddDetails1.setDetails("+5.00");
                    ddDetails1.setCreateTime(new Date());
                    ddDetailsMapper.insertDdDetails(ddDetails1);
                    User user2 = userMapper.selectUserByUserId(inviterId);
                    BigDecimal ddTotalNumber = user2.getDdTotalNumber();
                    user2.setDdTotalNumber(ddTotalNumber.add(BigDecimal.valueOf(5)));
                    user2.setCumulativeDd(user2.getCumulativeDd().add(BigDecimal.valueOf(5)));
                    user.setInviterId(inviterId);
                    userMapper.updateUser(user2);
                }
                userMapper.insertUser(user);

            }
            return AjaxResult.success("注册成功");
        }
    }


    /**
     * 修改专家密码
     *
     * @param expertPwd
     * @return
     */
    @Override
    public AjaxResult updateExpertPwd(ExpertPwd expertPwd) {
        String username = expertPwd.getUsername();
        String code = expertPwd.getCode();
        // 获取 RedisCache Bean
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        String redisKey = "sms:code:" + username;

        // 从 Redis 取出验证码
        String redisCode = redisCache.getCacheObject(redisKey);
        if (redisCode == null) {
            return AjaxResult.error("验证码已过期，请重新获取");
        } else if (!redisCode.equals(code)) {
            return AjaxResult.error("验证码错误");
        } else {
//            String userId = expertPwd.getUserId();
            String password = passwordEncoder.encode(expertPwd.getPassword());
            User user = new User();
            user.setUsername(expertPwd.getUsername() + "__expert");
            user.setPassword(password);
            userMapper.updatePwd(user);
            return AjaxResult.success("修改成功");
        }
    }

    /**
     * 用户端邀请码生成
     *
     * @param wxLoginVo
     * @return
     */
    @Override
    public AjaxResult QRCodeLogin(WxLoginVo wxLoginVo) {
        String str;
        int isExpert = wxLoginVo.getIsExpert();
        if (isExpert == 1) {
            // 微信小程序ID
            String appid = WxV3PayConfig.APP_ID;
            // 微信小程序秘钥
            String secret = WxV3PayConfig.secret;
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
            str = WeChatUtil.httpRequest(url, "GET", null);
        } else {
            String appId = "wx8348c4fdb4ade875";
            String secret = "675cdf892b3afb4381b9d323ebeae464";
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + secret;
            str = WeChatUtil.httpRequest(url, "GET", null);
        }
        return AjaxResult.success(str);
    }


//    public static void main(String[] args) {
//        String hash = "$2a$10$q1gXqskMtPH8G674z0x4PeQnjp38tt12T90w4EJ6n2qQIWxdXkPbG";
//        System.out.println(passwordEncoder.matches("hyk123456", hash)); // true 表示密码正确
//    }
}
